package com.task.scheduling.runner;

import com.task.scheduling.dao.TaskSchedulingDao;
import com.task.scheduling.enums.TaskStatus;
import com.task.scheduling.model.TaskResult;
import com.task.scheduling.model.TaskSchedulingModel;
import com.task.scheduling.processor.Processor;
import com.task.scheduling.processor.ProcessorTypes;
import com.task.scheduling.service.FutureHolder;
import com.task.scheduling.service.TaskHolder;
import com.task.scheduling.util.SpringContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.Semaphore;

/**
 * @program: task-scheduling
 * @description: 此类需要多利
 * @author: zhouliangliang
 * @create: 2019-03-08 17:20
 **/
@Component
@Scope("prototype")
public class ProcessorRunner implements Runnable{

    private Logger log = LoggerFactory.getLogger(ProcessorRunner.class);

    @Autowired
    private TaskSchedulingDao taskSchedulingDao;

    private TaskSchedulingModel task;

    private Semaphore semp;

    @Override
    public void run() {
        try {
            //内存持有任务
            TaskHolder.holdTask(task.getId());
            Processor processor = SpringContextUtil.getBean(ProcessorTypes.get(task.getTaskType()).getProcessor());
            //更新任务的执行时间
            taskSchedulingDao.updateDoTime(task.getId(), new Date(), new Date());
            //执行任务
            TaskResult result = processor.process(task);
            if(result.getTaskStatus() != TaskStatus.FAIL.getCode()) {
                //更新任务执行的状态
                TaskSchedulingModel upModel = new TaskSchedulingModel();
                upModel.setId(task.getId());
                upModel.setTaskStatus(result.getTaskStatus());
                upModel.setTaskMessage(result.getTaskMessage());
                upModel.setUpdateTime(new Date());
                taskSchedulingDao.updateTaskSchedule(upModel);
            } else if(result.getTaskStatus() == TaskStatus.FAIL.getCode()) {
                //更新任务的执行状态，失败是一个特殊的语句，记录执行次数
                taskSchedulingDao.updateTaskToFail(task.getId(), result.getTaskMessage(), new Date());
            }
        } catch (InterruptedException inte) {
            log.info("任务{}执行被中断，任务退出!", task.getId());
            //更新任务执行的状态
            TaskSchedulingModel upModel = new TaskSchedulingModel();
            upModel.setId(task.getId());
            upModel.setTaskStatus(TaskStatus.INTERRUPTED.getCode());
            upModel.setTaskMessage("任务{" + task.getId() +"}执行被中断，任务退出!");
            upModel.setUpdateTime(new Date());
            taskSchedulingDao.updateTaskSchedule(upModel);
        } catch (Exception e) {
            //任务执行失败了,更新任务状态为失败
            log.error("任务{}执行出错, 任务类型{}" + e.getMessage(), task.getId(), task.getTaskType(), e);
            taskSchedulingDao.updateTaskToFail(task.getId(), e.getMessage(), new Date());
        } finally {
            //放弃持有和信号量
            semp.release();
            //在执行任务记录器
            TaskHolder.removeTask(task.getId());
            //在执行任务和其对应的线程记录器
            FutureHolder.removeFuture(task.getId());
        }
    }

    public void setTask(TaskSchedulingModel task) {
        this.task = task;
    }

    public void setSemp(Semaphore semp) {
        this.semp = semp;
    }
}
